#include "stdafx.h"

#include "scene.h"
#include "connector.h"
#include "indicator.h"
#include "units.h"
#include "sensor_editor.h"

SceneView::SceneView(QWeakPointer<Common> _common)
	: common(_common)
{
	this->setBackgroundBrush(QBrush(QColor(49, 77, 116)));
	//this->setBackgroundBrush(QBrush(QColor(240, 240, 240)));
	redraw_virtual_connector = false;
}

SceneView::~SceneView() {
	virtual_item.clear();
	virtual_connector.clear();
}

void SceneView::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent){
	update();
	QGraphicsScene::mousePressEvent(mouseEvent);
}

void SceneView::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent){
	if (redraw_virtual_connector){
		virtual_connector.data()->adjust(mouseEvent->scenePos());
		foreach(QSharedPointer<ItemScene> item, list_of_items){
			foreach(QSharedPointer<ConnectionPoint> point, item.data()->getListOfConnectionPoint()){
				QPointF distance = point->pos() - mouseEvent->scenePos();
				point->setAccepted((point.data()->isAllowedAddConnector() && abs(distance.x()) < 10 && abs(distance.y()) < 10));
				point->update();
			}
		}
		bool find_intersect = false;
		pair<QPointF, int > intersect_param;
	
		foreach(QWeakPointer<Connector> connector, list_of_connectors)
			if (!virtual_connector.data()->source.data()->isChild(connector)){
				intersect_param = connector.data()->intersected(mouseEvent->scenePos());
				if (intersect_param.second != -1){
					if (!findInnerNodeNearMouse(mouseEvent->scenePos())){
						find_intersect = true;				
						break;
					}
				}
			}
		if (find_intersect){
			virtual_item = QSharedPointer<ItemScene>(new ItemScene(this, ItemScene::INNER_NODE));
			virtual_item->setPos(intersect_param.first);
			addItem(virtual_item.data());
		}else{
			virtual_item.clear();
		}
	}
	update();
	QGraphicsScene::mouseMoveEvent(mouseEvent);
}

bool SceneView::findInnerNodeNearMouse(const QPointF &_pos){
	foreach(QSharedPointer<ItemScene> item, list_of_items){
		if (item->getType() == ItemScene::INNER_NODE){
			QPointF distance = item->pos() - _pos;
			if (abs(distance.x()) < 25 && abs(distance.y()) < 25) return true;
		}
	}
	return false;
}

void SceneView::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent){
	if(redraw_virtual_connector){
		bool find_point = false;
		redraw_virtual_connector = false;
		foreach(QSharedPointer<ItemScene> item, list_of_items){
			foreach(QSharedPointer<ConnectionPoint> point, item.data()->getListOfConnectionPoint()){
				if(!find_point && point.data()->isAccepted() && point != virtual_connector.data()->source){
					addConnectorToScene(virtual_connector.data()->source, point);
					find_point = true;
				}
				point->setVisible(false);
				point->setAccepted(false);
			}
			item.data()->setFlag(QGraphicsItem::ItemIsMovable);
			item.data()->setFlag(QGraphicsItem::ItemIsSelectable);
		}
		
		if (!find_point){
			pair<QPointF, int > intersect_param;
			for(int i = 0; i < list_of_connectors.size(); i++){
				QSharedPointer<Connector> connector = list_of_connectors[i];
				if (!virtual_connector.data()->source.data()->isChild(connector)){
					intersect_param = connector.data()->intersected(mouseEvent->scenePos());
					if (intersect_param.second != -1){
						if (!findInnerNodeNearMouse(mouseEvent->scenePos())){
							QSharedPointer<ItemScene> item = addItemToScene(intersect_param.first, ItemScene::INNER_NODE);
							cutConnector(i, item->getListOfConnectionPoint()[0]);
							addConnectorToScene(virtual_connector.data()->source.data(), item->getListOfConnectionPoint()[0]);
							break;
							break;
						}

					}
				}
			}
			foreach(QSharedPointer<Connector> connector, list_of_connectors)
				connector->setMovable(true);
		}
		removeItem(virtual_item.data());
		removeItem(virtual_connector.data());
		virtual_item.clear();
		virtual_connector.clear();
	}
	update();
	QGraphicsScene::mouseReleaseEvent(mouseEvent);
}

void SceneView::keyPressEvent(QKeyEvent *event){
	switch (event->key()) {
	case Qt::Key_Delete :
		DeleteSelectedItem();
		break;
	}
}

void SceneView::keyReleaseEvent(QKeyEvent *event){
	
}

void SceneView::dragEnterEvent(QGraphicsSceneDragDropEvent *event){
	virtual_item = QSharedPointer<ItemScene>(new ItemScene(this, dropped_item));
	addItem(virtual_item.data());
}

void SceneView::dragMoveEvent(QGraphicsSceneDragDropEvent *event){
	virtual_item.data()->setPos(event->scenePos());
	virtual_item.data()->update();
}

void SceneView::dropEvent(QGraphicsSceneDragDropEvent *event){
	removeItem(virtual_item.data());
	addItemToScene(event->scenePos(), dropped_item);
}

void SceneView::dragLeaveEvent(QGraphicsSceneDragDropEvent *event){
	removeItem(virtual_item.data());
}

QSharedPointer<ItemScene> SceneView::addItemToScene(const QPointF &_pos, const ItemScene::itemType_t &_type, const QString &_name, const bool &_visibleTitle){
	if ((int)_type < 0)	return QSharedPointer<ItemScene>();
	QSharedPointer<ItemScene> item(new ItemScene(this, _type, _name, _pos));
	item->addConnectionPoint(item);
	item->setTitle(QSharedPointer<Title>(new Title(this, item, QPointF(0, - item->getSize().height() / 2), "", item->getStringType())));
	QStringList parameters;
	Units *unit_c = new Units;
	parameters = unit_c->getCalcParameters();
	Sensor* sensor = new Sensor(common, this, item->getTitleText(), parameters);
	sensor->setVisible(false);
	QSharedPointer<Indicator> indicator = QSharedPointer<Indicator>(new Indicator(common, this, sensor, QPointF(0, 50), false, sensor->getCalculatedParameters()));
	indicator->setIndicatorVisible(true);
	sensor->setIndicator(indicator);
	item->setSensor(sensor);
	item->setPosition(_pos);
	list_of_items.push_back(item);
	return item;
}

QSharedPointer<Connector> SceneView::addConnectorToScene(QWeakPointer<ConnectionPoint> _source, QWeakPointer<ConnectionPoint> _dest, const QString &_coordinates, const QPointF &_spot_pos){
	QSharedPointer<Spot> spot(new Spot(this));
	spot->setTitle(QSharedPointer<Title>(new Title(this, spot, QPointF(0, -8), "", "S")));
	QStringList parameters;
	Units *unit_c = new Units;
	parameters = unit_c->getCalcParameters();

	Sensor* sensor = new Sensor(common, this, spot->getTitleText(), parameters);
	sensor->setVisible(false);
	QSharedPointer<Indicator> indicator = QSharedPointer<Indicator>(new Indicator(common, this, sensor, QPointF(0, 50), false, sensor->getCalculatedParameters()));
	indicator->setIndicatorVisible(true);
	sensor->setIndicator(indicator);
	spot->setSensor(sensor);
	QSharedPointer<Connector> connector(new Connector(this, _source, _dest, spot, _coordinates));
	spot->addSource(connector);
	QPointF spot_pos = (_spot_pos != QPointF()) ? _spot_pos : connector.data()->getMiddlePoint();
	spot->setPos(spot->findClosestPoint(spot_pos));
	
	list_of_connectors.push_back(connector);
	_source.data()->addConnector(connector);
	_dest.data()->addConnector(connector);
	return connector;
}

void SceneView::cutConnector(int index, QWeakPointer<ConnectionPoint> point){
	if (index >= 0 && index < list_of_connectors.size()){
		QWeakPointer<Connector> connector = list_of_connectors[index];
		pair<QPointF, int > intersect_param = connector.data()->intersected(point.data()->pos());
		if (intersect_param.second != -1){	
			QString coordinates = connector.data()->get_lines_coordinate(intersect_param.second, intersect_param.first);
			connector.data()->dest.data()->removeConnector(connector);
			addConnectorToScene(point, connector.data()->dest, coordinates);
			connector.data()->dest = point;
			point.data()->addConnector(connector);
			for (int i = connector.data()->lines.size() - 1;  i > intersect_param.second; i--)
				connector.data()->lines.erase(connector.data()->lines.begin() + i);		
			connector.data()->lines[intersect_param.second]->dest = intersect_param.first;
			connector.data()->spot.data()->setPos(connector.data()->spot.data()->findClosestPoint(connector.data()->getMiddlePoint()));	
		}
	}
}


void SceneView::addVirtualConnector(QWeakPointer<ConnectionPoint> _point){
	virtual_connector = QSharedPointer<virtualConnector>(new virtualConnector(this, _point, _point.data()->pos()));
	foreach(QSharedPointer<ItemScene> item, list_of_items){
		foreach(QSharedPointer<ConnectionPoint> point, item.data()->getListOfConnectionPoint()){
			if (point.data()->isAllowedAddConnector())
				point->setVisible(true);
		}
		item.data()->setFlag(QGraphicsItem::ItemIsMovable, false);
		item.data()->setFlag(QGraphicsItem::ItemIsSelectable, false);
	}
	
	foreach(QSharedPointer<Connector> connector, list_of_connectors)
		connector->setMovable(false);
	redraw_virtual_connector = true;
}

void SceneView::DeleteSelectedItem(){
	foreach(QSharedPointer<ItemScene> item, list_of_items)
		if (item.data()->isSelected())
			eraseItemFromList(item);
	foreach(QSharedPointer<Connector> connector, list_of_connectors)
		if (connector.data()->spot.data()->isSelected())
			eraseConnectorFromList(connector);
}

void SceneView::eraseItemFromList(QWeakPointer<ItemScene> item){
	list_of_items.erase(find(list_of_items.begin(), list_of_items.end(), item));
	item.clear();
}

void SceneView::eraseConnectorFromList(QWeakPointer<Connector> connector){
	list_of_connectors.erase(find(list_of_connectors.begin(), list_of_connectors.end(), connector));
	connector.clear();
}

QSharedPointer<ItemScene> SceneView::findItemByName(const QString &_name){
	foreach(QSharedPointer<ItemScene> item, list_of_items){
		if(item.data()->getTitleText() == _name)
			return item;
	}
	return QSharedPointer<ItemScene>();
}

QSharedPointer<Connector> SceneView::findConnectorByName(const QString &_name){
	foreach(QSharedPointer<Connector> connector, list_of_connectors){
		if(connector.data()->spot->getTitleText() == _name)
			return connector;
	}
	return QSharedPointer<Connector>();
}

int SceneView::getIndexInList(ItemScene *item){
	for(int i = 0; i < list_of_items.size(); i++)
		if(item == list_of_items[i].data())
			return i;
	return -1;
}